package com.lin.controller;


import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.lin.constant.BookConstants;
import com.lin.constant.RecordConstants;
import com.lin.constant.RecordStatusConstants;
import com.lin.constant.UserConstants;
import com.lin.customEnum.RecordStatus;
import com.lin.entity.ErrorResponse;
import com.lin.entity.R;
import com.lin.entity.query.RecordQuery;
import com.lin.entity.vo.PageVO;
import com.lin.entity.vo.RecordVO;
import com.lin.entity.vo.RecordVO2;
import com.lin.entity.vo.UserVO;
import com.lin.exception.NoBorrowRecordException;
import com.lin.exception.RecordIdInvalidException;
import com.lin.exception.UnknownRecordStatusException;
import com.lin.service.IRecordService;
import com.lin.utils.JWTUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/records")
public class RecordController {
    @Resource
    private IRecordService recordService;

    /**
     * 查询指定图书的借阅记录
     * 先查询Redis中是否存在对应数据,
     * 如果存在则直接返回, 否则查询数据库并返回
     * @param bookId 图书ID
     * @return R
     */
    @GetMapping("/bookId/{bookId}")
    public R borrowBook(@PathVariable("bookId") Integer bookId) {
        RecordVO recordVO = null;
        try {
            recordVO = recordService.borrowBook(bookId);
        } catch (JsonProcessingException e) {
            R.error("获取借阅记录失败", null);
        }

        if (recordVO != null) {
            if (recordVO.getUserVO() != null) {
                return R.ok("图书已被借阅", recordVO);
            } else {
                return R.ok("借阅未被借阅", recordVO);
            }
        }
        return R.failed("图书信息不存在", null);
    }

    /**
     * 查询指定借阅记录的借阅状态 0-借阅中 1-已归还 [过期时间为30天]
     * 先查询Redis中是否存在对应数据,
     * 如果存在则直接返回, 否则查询数据库并返回
     * @param recordId 借阅记录ID
     * @return R
     */
    @GetMapping("/recordId/{recordId}")
    public R isExpired(@PathVariable("recordId") Integer recordId) {
        if (recordId == null || recordId <= 0)
            throw new RecordIdInvalidException("invalid recordId");

        // 查询借阅记录
        RecordStatus recordStatus = null;

        try {
            recordStatus = recordService.isExpired(recordId);
        } catch (JsonProcessingException e) {
            return R.error("获取借阅记录失败", null);
        }

        if (recordStatus == null) return R.failed(RecordStatus.LOST.getDescription(), null);

        // 判断借阅状态
        return R.ok(RecordStatus.fromCode(recordStatus.getStatus()), null);
    }

    /**
     * 获取当前用户借阅记录
     * 先查询Redis中是否存在对应数据,
     * 如果存在则直接返回, 否则查询数据库并返回
     * @param request 请求
     * @return R
     */
    @GetMapping
    public R getCurrentUserRecords(HttpServletRequest request) {
        String token = (String) request.getSession().getAttribute(RecordConstants.JWT_HEADER_INFO);

        String token_prefix = RecordConstants.TOKEN_PREFIX;

        // 去除token前缀
        if (token != null && token.startsWith(token_prefix)) {
            token = token.substring(token_prefix.length());
            DecodedJWT decodedJWT = JWTUtil.decodeAndVerify(token);

            // 获取当前用户名
            String username = decodedJWT.getClaim("username").asString();

            // 根据用户名查询用户信息 --用户名唯一
            List<RecordVO> currentUserRecords = null;

            try {
                currentUserRecords = recordService.getCurrentUserRecords(username);
            } catch (JsonProcessingException e) {
                R.error("获取当前用户借阅记录失败", null);
            }

            if (currentUserRecords != null && !currentUserRecords.isEmpty())
                return R.ok("获取当前用户借阅记录成功", currentUserRecords);

            return R.failed("获取当前用户借阅记录失败", null);
        }
        return R.failed("token为空, 用户未登录, 拒绝请求", null);
    }

    /**
     * 获取所有借阅记录
     * 先查询Redis中是否存在对应数据,
     * 如果存在则直接返回, 否则查询数据库并返回
     * @param recordQuery 查询参数
     * @return R
     */
    @GetMapping("/all")
    public R getAllRecords(@RequestBody RecordQuery recordQuery) {
        PageVO<RecordVO2> allRecords = null;

        try {
            allRecords = recordService.getAllRecords(recordQuery);
        } catch (JsonProcessingException e) {
            R.error("获取所有借阅记录失败", null);
        }

        if (allRecords != null)
            return R.ok("获取所有借阅记录成功", allRecords);

        return R.failed("获取所有借阅记录失败", null);
    }


    /**
     * NoBorrowRecordException 异常处理器
     * @param ex 异常信息
     * @return 响应实体
     */
    @ExceptionHandler(NoBorrowRecordException.class)
    public ResponseEntity<ErrorResponse> handleNoBorrowRecordException(NoBorrowRecordException ex) {
        ErrorResponse errorResponse = new ErrorResponse(RecordConstants.BORROW_RECORD_NOT_FOUND, ex.getMessage());
        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorResponse);
    }

    /**
     * RecordIdInvalidException 异常处理器
     * @param ex 异常信息
     * @return 响应实体
     */
    @ExceptionHandler(RecordIdInvalidException.class)
    public ResponseEntity<ErrorResponse> handleRecordIdInvalidException(RecordIdInvalidException ex) {
        ErrorResponse errorResponse = new ErrorResponse(RecordConstants.INVALID_RECORD_ID, ex.getMessage());
        return ResponseEntity.badRequest().body(errorResponse);
    }

    /**
     * UnknownRecordStatusException 异常处理器
     * @param ex 异常信息
     * @return 响应实体
     */
    @ExceptionHandler(UnknownRecordStatusException.class)
    public ResponseEntity<ErrorResponse> handleUnknownRecordStatusException(UnknownRecordStatusException ex) {
        ErrorResponse errorResponse = new ErrorResponse(RecordStatusConstants.UnKNOWN_RECORD_STATUS, ex.getMessage());
        return ResponseEntity.badRequest().body(errorResponse);
    }

    /**
     * TokenExpiredException 异常处理器
     * @param e 异常信息
     * @return 响应实体
     */
    @ExceptionHandler(TokenExpiredException.class)
    public R handleTokenExpiredException(TokenExpiredException e) {
        return R.failed("token已过期, 请重新登录", e);
    }
}
